<template>
    <div id="cesium-container">
    </div>
</template>
  
<script>
export default {
    name: 'PhotogrammetryClassification',
    components: {},
    mounted() {
        this.initViewer()
    },
    methods: {
        async initViewer() {
            Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIzM2RjYjJlOC01ZTQwLTQwODYtOTEwMy02M2U4OGEzYjQyNGUiLCJpZCI6MjI5NjUsInNjb3BlcyI6WyJhc3IiLCJnYyJdLCJpYXQiOjE1ODI0NTYwMzF9.VG2_T9ry8EnBWAh4msJ3s6m2jW_5hgAZQvfEQDh-WQs"
            const viewer = window.viewer = new window.Cesium.Viewer("cesium-container", {
                // terrainProvider: new window.Cesium.CesiumTerrainProvider({
                //     url: 'http://data.mars3d.cn/terrain',
                //     requestWaterMask: true,
                //     requestVertexNormals: true
                // }),
                imageryProvider: new window.Cesium.ArcGisMapServerImageryProvider({
                    url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'
                }),
                sceneMode: window.Cesium.SceneMode.SCENE3D,
                vrButton: false,
                animation: false,
                baseLayerPicker: false,
                geocoder: false,
                timeline: false,
                fullscreenButton: false,
                homeButton: false,
                creditContainer: document.createElement('div'),
                infoBox: false,
                navigationHelpButton: false,
                sceneModePicker: false,
                scene3DOnly: true,
                skyBox: new window.Cesium.SkyBox({
                    sources: {
                        positiveX: require('@/assets/images/tycho2t3_80_px.jpg'),
                        negativeX: require('@/assets/images/tycho2t3_80_mx.jpg'),
                        positiveY: require('@/assets/images/tycho2t3_80_py.jpg'),
                        negativeY: require('@/assets/images/tycho2t3_80_my.jpg'),
                        positiveZ: require('@/assets/images/tycho2t3_80_pz.jpg'),
                        negativeZ: require('@/assets/images/tycho2t3_80_mz.jpg'),
                    }
                })
            });
            window.viewer.scene.globe.depthTestAgainstTerrain = true;
            viewer.clock.currentTime = window.Cesium.JulianDate.fromIso8601(
                "2021-11-09T20:27:37.016064475348684937Z"
            );

            const scene = viewer.scene;

            const tileset = await new window.Cesium.Cesium3DTileset({
                url: window.Cesium.IonResource.fromAssetId(775877),
            }).readyPromise

            this.adjustTilesetHeight(tileset, 30)
            tileset.maximumScreenSpaceError = 8.0;
            scene.pickTranslucentDepth = true;
            scene.light.intensity = 7.0;
            viewer.scene.primitives.add(tileset);
            viewer.zoomTo(tileset);

            // Fly to a nice overview of the city.
            viewer.camera.flyTo({
                destination: new window.Cesium.Cartesian3(
                    -2703640.80485846,
                    -4261161.990345464,
                    3887439.511104276
                ),
                orientation: new window.Cesium.HeadingPitchRoll(
                    0.22426651143535548,
                    -0.2624145362506527,
                    0.000006972977223185239
                ),
            });

            // Styles =============================================================================

            const classificationStyle = new window.Cesium.Cesium3DTileStyle({
                color: "color(${color})",
            });

            const translucentWindowsStyle = new window.Cesium.Cesium3DTileStyle({
                color: {
                    conditions: [["${component} === 'Windows'", "color('gray', 0.7)"]],
                },
            });

            // Shaders ============================================================================

            // Dummy shader that sets the UNLIT lighting mode. For use with the classification style
            const emptyFragmentShader =
                "void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {}";
            const unlitShader = new window.Cesium.CustomShader({
                lightingModel: window.Cesium.LightingModel.UNLIT,
                fragmentShaderText: emptyFragmentShader,
            });

            const materialShader = new window.Cesium.CustomShader({
                lightingModel: window.Cesium.LightingModel.PBR,
                fragmentShaderText: `
                    const int WINDOW = 0;
                    const int FRAME = 1;
                    const int WALL = 2;
                    const int ROOF = 3;
                    const int SKYLIGHT = 4;
                    const int AIR_CONDITIONER_WHITE = 5;
                    const int AIR_CONDITIONER_BLACK = 6;
                    const int AIR_CONDITIONER_TALL = 7;
                    const int CLOCK = 8;
                    const int PILLARS = 9;
                    const int STREET_LIGHT = 10;
                    const int TRAFFIC_LIGHT = 11;
                    
                    void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
                    int featureId = fsInput.featureIds.featureId_0;
                    
                    if (featureId == CLOCK) {
                        // Shiny brass
                        material.specular = vec3(0.98, 0.90, 0.59);
                        material.roughness = 0.1;
                    } else if (
                        featureId == STREET_LIGHT ||
                        featureId == AIR_CONDITIONER_BLACK ||
                        featureId == AIR_CONDITIONER_WHITE ||
                        featureId == AIR_CONDITIONER_TALL ||
                        featureId == ROOF
                    ) {
                        // dull aluminum
                        material.specular = vec3(0.91, 0.92, 0.92);
                        material.roughness = 0.5;
                    } else if (featureId == WINDOW || featureId == SKYLIGHT) {
                        // make translucent, but also set an orange emissive color so it looks like
                        // it's lit from inside
                        material.emissive = vec3(1.0, 0.3, 0.0);
                        material.alpha = 0.5;
                    } else if (featureId == WALL || featureId == FRAME || featureId == PILLARS) {
                        // paint the walls and pillars white to contrast the brass clock
                        material.diffuse = mix(material.diffuse, vec3(1.0), 0.8);
                        material.roughness = 0.9;
                    } else {
                        // brighten everything else
                        material.diffuse += 0.05;
                        material.roughness = 0.9;
                    }
                    }
                    `,
            });

            const NOTHING_SELECTED = 12;
            const selectFeatureShader = new window.Cesium.CustomShader({
                uniforms: {
                    u_selectedFeature: {
                        type: window.Cesium.UniformType.INT,
                        value: NOTHING_SELECTED,
                    },
                },
                lightingModel: window.Cesium.LightingModel.PBR,
                fragmentShaderText: `
                    const int NOTHING_SELECTED = 12;
                    void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
                    int featureId = fsInput.featureIds.featureId_0;
                    
                    if (u_selectedFeature < NOTHING_SELECTED && featureId == u_selectedFeature) {
                        material.specular = vec3(1.00, 0.85, 0.57);
                        material.roughness = 0.1;
                    }
                    }
                    `,
            });

            const multipleFeatureIdsShader = new window.Cesium.CustomShader({
                uniforms: {
                    u_selectedFeature: {
                        type: window.Cesium.UniformType.FLOAT,
                        value: NOTHING_SELECTED,
                    },
                },
                lightingModel: window.Cesium.LightingModel.UNLIT,
                fragmentShaderText: `
                    const int IDS0_WINDOW = 0;
                    const int IDS1_FACADE = 2;
                    const int IDS1_ROOF = 3;
                    const vec3 PURPLE = vec3(0.5, 0.0, 1.0);
                    const vec3 YELLOW = vec3(1.0, 1.0, 0.0);
                    const vec3 NO_TINT = vec3(1.0);
                    
                    void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
                    int featureId0 = fsInput.featureIds.featureId_0; // fine features
                    int featureId1 = fsInput.featureIds.featureId_1; // coarse features
                    
                    // use both feature ID sets to determine where the features are
                    float isWindow = float(featureId0 == IDS0_WINDOW);
                    float isFacade = float(featureId1 == IDS1_FACADE);
                    float isRoof = float(featureId1 == IDS1_ROOF);
                    
                    // Tint the roof windows yellow and facade windows purple
                    vec3 tint = NO_TINT;
                    tint = mix(tint, YELLOW, isWindow * isRoof);
                    tint = mix(tint, PURPLE, isWindow * isFacade);
                    material.diffuse *= tint;
                    }
                    `,
            });

            // Demo Functions =====================================================================

            function defaults() {
                tileset.style = undefined;
                tileset.customShader = unlitShader;
                tileset.colorBlendMode = window.Cesium.Cesium3DTileColorBlendMode.HIGHLIGHT;
                tileset.colorBlendAmount = 0.5;
                tileset.featureIdLabel = 0;
            }

            const showPhotogrammetry = defaults;

            function showClassification() {
                defaults();
                tileset.style = classificationStyle;
                tileset.colorBlendMode = window.Cesium.Cesium3DTileColorBlendMode.MIX;
            }

            function showAlternativeClassification() {
                showClassification();
                // This dataset has a second feature ID texture.
                tileset.featureIdLabel = 1;
            }

            function translucentWindows() {
                defaults();
                tileset.style = translucentWindowsStyle;
            }

            function pbrMaterials() {
                defaults();
                tileset.customShader = materialShader;
            }

            function goldenTouch() {
                defaults();
                tileset.customShader = selectFeatureShader;
            }

            function multipleFeatureIds() {
                defaults();
                tileset.customShader = multipleFeatureIdsShader;
            }

            // Pick Handlers ======================================================================

            // HTML overlay for showing feature name on mouseover
            const nameOverlay = document.createElement("div");
            viewer.container.appendChild(nameOverlay);
            nameOverlay.className = "backdrop";
            nameOverlay.style.display = "none";
            nameOverlay.style.position = "absolute";
            nameOverlay.style.bottom = "0";
            nameOverlay.style.left = "0";
            nameOverlay.style["pointer-events"] = "none";
            nameOverlay.style.padding = "4px";
            nameOverlay.style.backgroundColor = "black";
            nameOverlay.style.color = "white";
            nameOverlay.style.whiteSpace = "pre-line";
            nameOverlay.style.fontSize = "12px";

            let enablePicking = true;
            const handler = new window.Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
            handler.setInputAction(function (movement) {
                if (enablePicking) {
                    const pickedObject = viewer.scene.pick(movement.endPosition);
                    if (pickedObject instanceof window.Cesium.Cesium3DTileFeature) {
                        nameOverlay.style.display = "block";
                        nameOverlay.style.bottom = `${viewer.canvas.clientHeight - movement.endPosition.y
                            }px`;
                        nameOverlay.style.left = `${movement.endPosition.x}px`;
                        const component = pickedObject.getProperty("component");
                        const message = `Component: ${component}\nFeature ID: ${pickedObject.featureId}`;
                        nameOverlay.textContent = message;
                    } else {
                        nameOverlay.style.display = "none";
                    }
                } else {
                    nameOverlay.style.display = "none";
                }
            }, window.Cesium.ScreenSpaceEventType.MOUSE_MOVE);

            handler.setInputAction(function (movement) {
                if (enablePicking) {
                    const pickedObject = scene.pick(movement.position);
                    if (
                        window.Cesium.defined(pickedObject) &&
                        window.Cesium.defined(pickedObject.featureId)
                    ) {
                        selectFeatureShader.setUniform(
                            "u_selectedFeature",
                            pickedObject.featureId
                        );
                    } else {
                        selectFeatureShader.setUniform(
                            "u_selectedFeature",
                            NOTHING_SELECTED
                        );
                    }
                }
            }, window.Cesium.ScreenSpaceEventType.LEFT_CLICK);

            let action = 'showPhotogrammetry'
            switch (action) {
                case 'showPhotogrammetry':
                    showPhotogrammetry()
                    break;
                case 'showClassification':
                    showClassification()
                    break;
                case 'showAlternativeClassification':
                    showAlternativeClassification()
                    break;
                case 'translucentWindows':
                    translucentWindows()
                    break;
                case 'pbrMaterials':
                    pbrMaterials()
                    break;
                case 'goldenTouch':
                    goldenTouch()
                    break;
                case 'multipleFeatureIds':
                    multipleFeatureIds()
                    break;
            }

        },
        adjustTilesetHeight(tileset, height = 10) {
            //计算出模型包围球的中心点(弧度制)
            const cartographic = window.Cesium.Cartographic.fromCartesian(
                tileset.boundingSphere.center
            );
            //计算与模型包围球中心点经纬度相同的地表点位
            const surface = window.Cesium.Cartesian3.fromRadians(
                cartographic.longitude,
                cartographic.latitude,
                0.0
            );
            //计算调整高度后的模型包围球的中心点
            const offset = window.Cesium.Cartesian3.fromRadians(
                cartographic.longitude,
                cartographic.latitude,
                height
            );
            //计算差向量
            const translation = window.Cesium.Cartesian3.subtract(
                offset,
                surface,
                new window.Cesium.Cartesian3()
            );
            //修改模型的变换矩阵
            tileset.modelMatrix = window.Cesium.Matrix4.fromTranslation(translation);
        }
    }
}
</script>
  
<style>
#cesium-container {
    width: 100%;
    height: 100%;
}
</style>
  